package raytracing;
import util.Vector3f;

/**
 * A ray, represented by it's starting point e and it's destination s
 * 
 * @author glenn
 *
 */
public class Ray {
	
	/**
	 * The starting point
	 */
	private Vector3f e;
	
	/**
	 * The destination point
	 */
	private Vector3f s;
	
	private Vector3f d;
	
	/**
	 * Constructs a ray, starting in the origin and shooting along the x-axis
	 */
	public Ray(){
		this.e = new Vector3f(0,0,0);
		this.s = new Vector3f(1,0,0);
		this.d = s.subtract(e);
	}
	
	/**
	 * Constructs a ray through point e (eye) and s.
	 * Otherwise said: with origin e and direction (s-e).
	 * @param e
	 * @param s
	 */
	public Ray(Vector3f e, Vector3f s){
		this.e = e;
		this.s = s;
		this.d = s.subtract(e);
	}
	
	/**
	 * Returns the first (starting) point of this ray
	 * @return the starting point e
	 */
	public Vector3f getE(){
		return e;
	}
	
	/**
	 * Returns the second (end/destination) point of this ray
	 * @return the end point s
	 */
	public Vector3f getS(){
		return s;
	}
	
	/**
	 * Returns the point at fractional distance t along the ray
	 * @param t the fractional distance at which the resulting point resides
	 * @return the point p at fractional distance t along the ray
	 */
	public Vector3f param(float t){
		return e.add(getDirection().scale(t)); //p(t) = e + t * (s-e)
	}
	
	/**
	 * @return The direction of the ray, normalized
	 */
	public Vector3f getDirection(){
		return d;
	}
	
	/**
	 * @return The origin point of the ray
	 */
	public Vector3f getOrigin(){
		return e;
	}
	
	public Interval getRangeX(){
		float start = s.x, dx = getDirection().x;
		if(dx < 0)
			return new Interval(Float.NEGATIVE_INFINITY, start);
		else if(dx > 0)
			return new Interval(start, Float.POSITIVE_INFINITY);
		return new Interval(start, start);
	}
	
	public Interval getRangeY(){
		float start = s.y, dy = getDirection().y;
		if(dy < 0)
			return new Interval(Float.NEGATIVE_INFINITY, start);
		else if(dy > 0)
			return new Interval(start, Float.POSITIVE_INFINITY);
		return new Interval(start, start);
	}
	
	public Interval getRangeZ(){
		float start = s.z, dz = getDirection().z;
		if(dz < 0)
			return new Interval(Float.NEGATIVE_INFINITY, start);
		else if(dz > 0)
			return new Interval(start, Float.POSITIVE_INFINITY);
		return new Interval(start, start);
	}
	
}
